Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(experimental): Issue errors for unreachable match branches #7556

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

jfecher
Copy link
Contributor

@jfecher jfecher commented Feb 28, 2025

Description

Problem*

Resolves

Summary*

Implements "unreachable case" errors for patterns in match expressions that are redundant with other patterns.

Additional Context

This took more time than expected. While the initial error was easy it was surprisingly difficult to get it to stop erroring if there were also any other errors in constructing the match rows. E.g. a program like

match Some(3) {
    Some(x) => (),
    3 => (),
    None => (),
    None => (),
}

Will give a type error on 3 => (), but will also give a separate error saying that it is unreachable. This extra error broke existing match tests (which mostly only expect 1 error) and was difficult to remove since it is technically correct. In the end I opted to not compile the decision tree of a match at all if there were any errors in constructing the pattern rows. This is what Ante does and it seems to match Rust as well. Neither of those languages issue errors for obviously redundant cases like the second None => (), if there was a type error or a name resolution error in constructing the match tree.

Documentation*

Check one:

  • No documentation needed.
  • Documentation included in this PR.
  • [For Experimental Features] Documentation to be submitted in a separate PR.

PR Checklist*

  • I have tested the changes locally.
  • I have formatted the changes with Prettier and/or cargo fmt on default settings.

@jfecher jfecher requested a review from a team February 28, 2025 16:40
@jfecher jfecher changed the title Jf/unreachable case error feat(experimental): Issue errors for unreachable match branches Feb 28, 2025
Comment on lines +40 to +103
/// A Pattern is anything that can appear before the `=>` in a match rule.
#[derive(Debug, Clone)]
enum Pattern {
/// A pattern checking for a tag and possibly binding variables such as `Some(42)`
Constructor(Constructor, Vec<Pattern>),
/// An integer literal pattern such as `4`, `12345`, or `-56`
Int(SignedField),
/// A pattern binding a variable such as `a` or `_`
Binding(DefinitionId),

/// Multiple patterns combined with `|` where we should match this pattern if any
/// constituent pattern matches. e.g. `Some(3) | None` or `Some(1) | Some(2) | None`
#[allow(unused)]
Or(Vec<Pattern>),

/// An integer range pattern such as `1..20` which will match any integer n such that
/// 1 <= n < 20.
#[allow(unused)]
Range(SignedField, SignedField),

/// An error occurred while translating this pattern. This Pattern kind always translates
/// to a Fail branch in the decision tree, although the compiler is expected to halt
/// with errors before execution.
Error,
}

#[derive(Clone)]
struct Column {
variable_to_match: DefinitionId,
pattern: Pattern,
}

impl Column {
fn new(variable_to_match: DefinitionId, pattern: Pattern) -> Self {
Column { variable_to_match, pattern }
}
}

#[derive(Clone)]
pub(super) struct Row {
columns: Vec<Column>,
guard: Option<RowBody>,
body: RowBody,
original_body: RowBody,
location: Location,
}

type RowBody = ExprId;

impl Row {
fn new(columns: Vec<Column>, guard: Option<RowBody>, body: RowBody, location: Location) -> Row {
Row { columns, guard, body, original_body: body, location }
}
}

impl Row {
fn remove_column(&mut self, variable: DefinitionId) -> Option<Column> {
self.columns
.iter()
.position(|c| c.variable_to_match == variable)
.map(|idx| self.columns.remove(idx))
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this was just moved from the bottom of the file to the top.

The only change is the addition of original_body: RowBody and location: Location in Row

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant